<?php

/**
 * +----------------------------------------------------------------------
 * | TickyPHP [ This is a freeware ]
 * +----------------------------------------------------------------------
 * | Copyright (c) 2015 All rights reserved.
 * +----------------------------------------------------------------------
 * | Author: 罗敏贵 <e-mail:minguiluo@163.com> <QQ:271391233>
 * +----------------------------------------------------------------------
 * | SVN: $Id: param.php 09594 2018-09-04 09:29:53 luomingui $
 * +----------------------------------------------------------------------
 * | 文件功能：路由
 * +----------------------------------------------------------------------
 */

namespace ticky;

use ticky\helper\file;

class route {

    /**
     * @var bool 是否初始化过
     */
    protected static $init = false;
    protected static $config = null;  //路由配置
    protected static $handler = null;    //当前控制器实例化句柄

    /**
     * 路由分发
     */

    static public function dispatch() {
        self::getconfig();
        defined('MODULE_NAME') or define('MODULE_NAME', self::route_m()); //定义当前模块名常量
        defined('CONTROLLER_NAME') or define('CONTROLLER_NAME', self::route_c()); //定义当前控制器名常量
        defined('ACTION_NAME') or define('ACTION_NAME', self::route_a()); //定义当前方法名常量

        define('MODULE_PATH', APP_PATH . DS . MODULE_NAME); //定义当前模块目录常量
        define('CONTROLLER_PATH', MODULE_PATH . DS . 'controller'); //定义当前模块控制器目录常量
        define('MODEL_PATH', MODULE_PATH . DS . 'model'); //定义当前模块模型目录常量
        define('VIEW_PATH', MODULE_PATH . DS . 'view'); //定义当前模块视图目录常量
        define('CONFIG_PATH', MODULE_PATH . DS . 'config'); //定义当前模块配置目录常量
        define('FILTER_PATH', MODULE_PATH . DS . 'filter'); //定义当前模块过滤器目录常量
        //拼装完整控制器类名
        $fullController = app::$namespace . '\\' . MODULE_NAME . '\\' . 'controller\\' . CONTROLLER_NAME;

        if (!is_dir(APP_PATH . DS . MODULE_NAME)) {
            app::halt('module does not exist : ' . MODULE_NAME);
        }
        if (!class_exists($fullController)) {
            app::halt('Controller does not exist : ' . $fullController);
        }
        if (!method_exists($fullController, ACTION_NAME) && !method_exists($fullController, '__call')) {
            app::halt('Action does not exist : ' . ACTION_NAME);
        }

        //加载模块资源
        self::load_model_resources();
        // 单例模式实例化控制器
        if (!(self::$handler)) {
            self::$handler = new $fullController();
        }
        // 执行控制方法
        $ret = call_user_func([self::$handler, ACTION_NAME]);
        if (APP_DEBUG) {
            if (!request::isAjax()) {
                if (!(MODULE_NAME == "admin" && CONTROLLER_NAME == "index" && ACTION_NAME == "index")) {
                    debug::stop();
                    if (!defined('DEBUG_HIDDEN')) {
                        debug::message();
                    }
                }
            }
        }
        return $ret;
    }

    /**
     * 获取模型
     */
    static public function route_m() {
        $m = isset($_GET['m']) && !empty($_GET['m']) ? $_GET['m'] : (isset($_POST['m']) && !empty($_POST['m']) ? $_POST['m'] : '');
        $m = self::safe_deal($m);
        if (empty($m)) {
            return self::$config['default_module'];
        } else {
            if (is_string($m))
                return $m;
        }
    }

    /**
     * 获取控制器
     */
    static public function route_c() {
        $c = isset($_GET['c']) && !empty($_GET['c']) ? $_GET['c'] : (isset($_POST['c']) && !empty($_POST['c']) ? $_POST['c'] : '');
        $c = self::safe_deal($c);
        if (empty($c)) {
            $c = self::$config['default_controller'];
        }
        return $c;
    }

    /**
     * 获取事件
     */
    static public function route_a() {
        $a = isset($_GET['a']) && !empty($_GET['a']) ? $_GET['a'] : (isset($_POST['a']) && !empty($_POST['a']) ? $_POST['a'] : '');
        $a = self::safe_deal($a);
        if (empty($a)) {
            return self::$config['default_action'];
        } else {
            if (is_string($a))
                return $a;
        }
    }

    /**
     * URL组装 支持不同URL模式
     * @param string $url URL表达式，格式：'[模块/控制器/操作]'
     * @param string|array $vars 传入的参数，支持字符串和数组
     * @param boolean $domain 是否显示域名
     * @return string
     */
    static public function url($url = '', $vars = '', $domain = false) {

        $url = trim($url, '/');
        $arr = explode('/', $url);
        $num = count($arr);

        $string = SITE_PATH;
        if (URL_MODEL == 0) {
            $string .= 'index.php?';
            if ($num == 3) {
                $string .= 'm=' . $arr[0] . '&c=' . $arr[1] . '&a=' . $arr[2];
            } elseif ($num == 2) {
                $string .= 'm=' . MODULE_NAME . '&c=' . $arr[0] . '&a=' . $arr[1];
            } else {
                $string .= 'm=' . MODULE_NAME . '&c=' . CONTROLLER_NAME . '&a=' . $arr[0];
            }

            if ($vars) {
                if (is_array($vars))
                    $vars = http_build_query($vars);
                $string .= '&' . $vars;
            }
        }else {
            if (URL_MODEL == 1) {
                $string .= 'index.php?s=';
            }
            if ($num == 3) {
                $string .= $url;
            } elseif ($num == 2) {
                $string .= MODULE_NAME . '/' . $url;
            } else {
                $string .= MODULE_NAME . '/' . CONTROLLER_NAME . '/' . $url;
            }
            if ($vars) {
                if (!is_array($vars)) {
                    parse_str($vars, $vars);
                }
                foreach ($vars as $var => $val) {
                    if (trim($val) !== '') {
                        $string .= '/' . urlencode($var) . '/' . urlencode($val);
                    }
                }
            }
            $string .= self::$config['default_extension'];
        }

        if (URL_MODEL == 3 || $domain) {
            $string = SERVER_PORT . HTTP_HOST . $string;
        }
        return $string;
    }

    /**
     * 安全处理函数
     * 处理m,a,c
     */
    static private function safe_deal($str) {
        if (!MAGIC_QUOTES_GPC)
            $str = addslashes($str);
        return str_replace(array('/', '.'), '', $str);
    }

    static private function getconfig() {
        if (is_null(self::$config)) {
            self::$config = config('http');
        }
        if (URL_MODEL != 0) {
            if (self::$config['set_pathinfo']) {
                self::set_pathinfo();
            }
            self::pathinfo_url();
        }
        return true;
    }

    /**
     * 设置PATHINFO
     */
    static private function set_pathinfo() {
        if (isset($_GET['s']) && !empty($_GET['s']))
            return;
        $pathinfo = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['REQUEST_URI']);

        if ($pathinfo) {
            $pathinfo = urldecode($pathinfo);
            $pos = strpos($pathinfo, '?');
            if ($pos !== false)
                $pathinfo = substr($pathinfo, 0, $pos);
            if ($pathinfo)
                $_GET['s'] = $pathinfo;
        }
    }

    /**
     * 解析PATH_INFO模式
     */
    static private function pathinfo_url() {
        if (!isset($_SERVER['PATH_INFO'])) {
            $_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI'];
        }
        if (!isset($_GET['s'])) {
            return false;
        }
        $_SERVER['PATH_INFO'] = $_GET['s'];

        unset($_GET['s']);
        if (isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO'])) {
            $_SERVER['PATH_INFO'] = str_ireplace(array(self::$config['default_extension'], 'index.php'), '', $_SERVER['PATH_INFO']);
            if (self::$config['route_mapping']) {
                self::mapping(set_mapping());
            }

            $pathinfo = explode('/', trim($_SERVER['PATH_INFO'], '/'));
            $_GET['m'] = isset($pathinfo[0]) ? $pathinfo[0] : '';
            $_GET['c'] = isset($pathinfo[1]) ? $pathinfo[1] : '';
            $_GET['a'] = isset($pathinfo[2]) ? $pathinfo[2] : '';

            for ($i = 3; $i < count($pathinfo); $i += 2) {
                if (isset($pathinfo[$i + 1])) {
                    $_GET[$pathinfo[$i]] = $pathinfo[$i + 1];
                }
            }
        }
        return true;
    }

    /**
     * 路由映射
     */
    static private function mapping($rules) {
        if (!is_array($rules))
            return;
        $pathinfo = trim($_SERVER['PATH_INFO'], '/');
        foreach ($rules as $k => $v) {
            $reg = '/' . $k . '/i';
            if (preg_match($reg, $pathinfo)) {
                $res = preg_replace($reg, $v, $pathinfo);
                $_SERVER['PATH_INFO'] = '/' . $res;
            }
        }
    }

    //加载模块资源
    static private function load_model_resources() {

        //加载模块语言
        Lang::load([
            APP_PATH . DS . MODULE_NAME . DS . 'lang' . DS . strtolower(lang::range()) . ".php",
        ]);
        $configFile = [
            //加载模块 function
            '1' => APP_PATH . DS . MODULE_NAME . DS . 'function' . DS . 'function.php',
            '2' => APP_PATH . DS . MODULE_NAME . DS . 'function' . DS . 'function_' . MODULE_NAME . '.php',
            '3' => APP_PATH . DS . MODULE_NAME . DS . 'function' . DS . 'function_' . CONTROLLER_NAME . '.php',
            //include
            '4' => APP_PATH . DS . MODULE_NAME . DS . 'include' . DS . 'include.php',
            '5' => APP_PATH . DS . MODULE_NAME . DS . 'include' . DS . 'include_' . MODULE_NAME . '.php',
            '6' => APP_PATH . DS . MODULE_NAME . DS . 'include' . DS . 'include_' . CONTROLLER_NAME . '.php',
        ];
        //debug($configFile);
        foreach ($configFile as $x => $x_value) {
            if (is_file($x_value)) {
                file::load($x_value);
            }
        }
        loader::addNamespace('application', APP_PATH . MODULE_NAME . DS . 'extend');
    }

}
